package com.lucifer.treasure.enchant.effect;

import com.lucifer.treasure.registry.EnchantRegistry;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentEffectContext;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeType;
import net.minecraft.recipe.SmeltingRecipe;
import net.minecraft.recipe.input.SingleStackRecipeInput;
import net.minecraft.registry.Registries;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;

import java.util.*;

public record ExcavationEnchantmentEffect(EnchantmentLevelBasedValue maxBlocks) implements EnchantmentEntityEffect {
    public static final MapCodec<ExcavationEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                    EnchantmentLevelBasedValue.CODEC.fieldOf("max_blocks").forGetter(ExcavationEnchantmentEffect::maxBlocks)
            ).apply(instance, ExcavationEnchantmentEffect::new)
    );

    public static void initialize() {
        PlayerBlockBreakEvents.AFTER.register((world, player, pos, state, blockEntity) -> {
            // 首先检查配置是否启用此附魔
            if (!EnchantRegistry.isEnchantEnabled("excavation")) {
                return;
            }

            if (world.isClient() || !(player instanceof PlayerEntity)) {
                return;
            }

            ItemStack tool = player.getMainHandStack();
            if (tool.isEmpty()) {
                return;
            }

            // 检查工具是否有Excavation附魔
            var enchantments = EnchantmentHelper.getEnchantments(tool);
            boolean hasExcavation = false;
            int excavationLevel = 0;

            for (var entry : enchantments.getEnchantments()) {
                if (entry.getKey().isPresent()) {
                    String enchantmentId = entry.getKey().get().getValue().toString();
                    if (enchantmentId.equals("lucifer_treasure:excavation")) {
                        hasExcavation = true;
                        excavationLevel = enchantments.getLevel(entry);
                        break;
                    }
                }
            }

            if (!hasExcavation || excavationLevel <= 0) {
                return;
            }

            // 检查是否是可挖掘的方块（避免挖掘基岩、空气等）
            if (state.isAir() || state.getHardness(world, pos) < 0) {
                return;
            }

            // 检查是否是矿物方块，只对矿物生效
            if (!isOreBlock(state)) {
                return;
            }

            // 开始连锁挖掘
            int maxBlocks = getHarvestMax(excavationLevel);
            Set<BlockPos> harvestedBlocks = new HashSet<>();
            harvestSurrounding((ServerWorld) world, player, pos, state, harvestedBlocks, maxBlocks, tool);

            // 连锁挖掘完成后，聚合所有掉落物到第一个方块位置
            if (harvestedBlocks.size() > 1) { // 只有在真正连锁挖掘时才聚合
                // 延迟执行聚合，确保所有掉落物都已生成
                world.getServer().execute(() -> {
                    gatherDropsToCenter((ServerWorld) world, pos, harvestedBlocks);
                });
            }
        });
    }

    /**
     * 检查是否是矿物方块
     */
    private static boolean isOreBlock(BlockState state) {
        String blockId = Registries.BLOCK.getId(state.getBlock()).toString();

        // 检查是否包含"ore"关键词或特定矿物名称
        return blockId.contains("_ore") ||
                blockId.contains("coal_ore") ||
                blockId.contains("iron_ore") ||
                blockId.contains("gold_ore") ||
                blockId.contains("diamond_ore") ||
                blockId.contains("emerald_ore") ||
                blockId.contains("lapis_ore") ||
                blockId.contains("redstone_ore") ||
                blockId.contains("copper_ore") ||
                blockId.contains("nether_gold_ore") ||
                blockId.contains("nether_quartz_ore") ||
                blockId.contains("ancient_debris") ||
                // 包含原木类型（可选，如果你想要连锁砍树）
                // blockId.contains("_log") ||
                // blockId.contains("_wood") ||
                // 其他mod的矿物（通用检测）
                blockId.endsWith("_ore") ||
                blockId.contains("ore_");
    }

    private static int getHarvestMax(int level) {
        return Math.min(8 + 8 * level, 64); // 基础8个方块，每级增加8个，最大64个
    }

    private static void harvestSurrounding(ServerWorld world, PlayerEntity player, BlockPos centerPos,
                                           BlockState targetState, Set<BlockPos> harvestedBlocks, int maxBlocks, ItemStack tool) {

        if (harvestedBlocks.size() >= maxBlocks || tool.isEmpty()) {
            return;
        }

        Queue<BlockPos> toCheck = new LinkedList<>();
        toCheck.add(centerPos);
        harvestedBlocks.add(centerPos);
        Block targetBlock = targetState.getBlock();

        while (!toCheck.isEmpty() && harvestedBlocks.size() < maxBlocks) {
            BlockPos currentPos = toCheck.poll();

            // 检查所有26个方向（包括对角线）
            for (int dx = -1; dx <= 1; dx++) {
                for (int dy = -1; dy <= 1; dy++) {
                    for (int dz = -1; dz <= 1; dz++) {
                        // 跳过中心点（0,0,0）
                        if (dx == 0 && dy == 0 && dz == 0) {
                            continue;
                        }

                        BlockPos neighborPos = currentPos.add(dx, dy, dz);

                        if (harvestedBlocks.contains(neighborPos) || harvestedBlocks.size() >= maxBlocks) {
                            continue;
                        }

                        // 距离限制：防止挖掘过远
                        if (Math.abs(neighborPos.getX() - centerPos.getX()) > 8 ||
                                Math.abs(neighborPos.getY() - centerPos.getY()) > 8 ||
                                Math.abs(neighborPos.getZ() - centerPos.getZ()) > 8) {
                            continue;
                        }

                        BlockState neighborState = world.getBlockState(neighborPos);

                        // 检查是否是相同类型的方块
                        if (neighborState.getBlock() == targetBlock) {
                            // 检查玩家是否可以破坏这个方块
                            if (canHarvestBlock(world, player, neighborPos, neighborState, tool)) {
                                // 破坏方块并掉落物品
                                Block.dropStacks(neighborState, world, neighborPos, world.getBlockEntity(neighborPos), player, tool);
                                world.breakBlock(neighborPos, false);

                                // 立即处理自动熔炼（如果工具有该附魔）
                                processAutoSmeltForPos(world, player, neighborPos, tool);

                                harvestedBlocks.add(neighborPos);
                                toCheck.add(neighborPos);

                                // 损耗工具耐久度
                                if (!player.isCreative() && !tool.isEmpty()) {
                                    tool.damage(1, player, net.minecraft.entity.EquipmentSlot.MAINHAND);
                                    if (tool.getDamage() >= tool.getMaxDamage()) {
                                        return; // 工具损坏，停止挖掘
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private static boolean canHarvestBlock(ServerWorld world, PlayerEntity player, BlockPos pos,
                                           BlockState state, ItemStack tool) {
        // 基本检查
        if (state.isAir() || !player.canModifyBlocks()) {
            return false;
        }

        // 检查硬度（避免挖掘基岩等）
        if (state.getHardness(world, pos) < 0) {
            return false;
        }

        // 检查工具是否有效（使用更宽松的检查）
        if (!tool.isSuitableFor(state)) {
            return false;
        }

        // 检查是否在保护区域内
        if (!world.canPlayerModifyAt(player, pos)) {
            return false;
        }

        // 避免挖掘某些特殊方块
        String blockId = Registries.BLOCK.getId(state.getBlock()).toString();
        if (blockId.contains("bedrock") || blockId.contains("barrier") ||
                blockId.contains("portal") || blockId.contains("spawner")) {
            return false;
        }

        return true;
    }

    /**
     * 处理指定位置的自动熔炼
     */
    private static void processAutoSmeltForPos(ServerWorld world, PlayerEntity player, BlockPos pos, ItemStack tool) {
        // 检查工具是否有AutoSmelt附魔
        var enchantments = EnchantmentHelper.getEnchantments(tool);
        boolean hasAutoSmelt = false;

        for (var entry : enchantments.getEnchantments()) {
            if (entry.getKey().isPresent()) {
                String enchantmentId = entry.getKey().get().getValue().toString();
                                        if (enchantmentId.equals("lucifer_treasure:auto_smelt")) {
                    hasAutoSmelt = true;
                    break;
                }
            }
        }

        if (!hasAutoSmelt) {
            return;
        }

        // 查找附近的掉落物并熔炼它们
        smeltNearbyDrops(world, pos);
    }

    /**
     * 熔炼指定位置附近的掉落物
     */
    private static void smeltNearbyDrops(ServerWorld world, BlockPos pos) {
        // 在方块位置周围1.5格范围内查找掉落物
        List<ItemEntity> nearbyItems = world.getEntitiesByClass(ItemEntity.class,
                new net.minecraft.util.math.Box(pos).expand(1.5),
                item -> item.isAlive() && item.age < 20); // 扩大时间窗口到20ticks

        // 查找附近的玩家来检查经验提升附魔
        PlayerEntity nearestPlayer = world.getClosestPlayer(pos.getX(), pos.getY(), pos.getZ(), 8.0, false);

        for (ItemEntity itemEntity : nearbyItems) {
            ItemStack originalStack = itemEntity.getStack();
            ItemStack smeltedResult = getSmeltedResult(originalStack, world);

            if (!smeltedResult.isEmpty()) {
                // 计算并生成熔炼经验
                float smeltingExp = getSmeltingExperience(originalStack, world);
                if (smeltingExp > 0) {
                    int totalExp = Math.round(smeltingExp * originalStack.getCount());

                    // 如果玩家有经验提升附魔，增加熔炼经验
                    if (nearestPlayer != null) {
                        ItemStack tool = nearestPlayer.getMainHandStack();
                        if (!tool.isEmpty()) {
                            var enchantments = EnchantmentHelper.getEnchantments(tool);
                            for (var entry : enchantments.getEnchantments()) {
                                if (entry.getKey().isPresent()) {
                                    String enchantmentId = entry.getKey().get().getValue().toString();
                                    if (enchantmentId.equals("lucifer_treasure:experience_boost")) {
                                        int level = enchantments.getLevel(entry);
                                        // 大幅增强熔炼经验倍数
                                        // 基础倍数：10倍熔炼经验 + 经验提升等级的额外加成
                                        double baseMultiplier = 10.0; // 基础10倍经验
                                        // 应用经验提升：每级增加3倍经验，开平方提供递减收益
                                        double levelMultiplier = (level * 3.0) + Math.sqrt(level * 5.0);
                                        double finalMultiplier = baseMultiplier + levelMultiplier;
                                        totalExp = (int) Math.round(totalExp * finalMultiplier);
                                        break;
                                    }
                                }
                            }
                        }
                    } else {
                        // 即使没有经验提升附魔，自动熔炼本身也给予5倍基础经验
                        totalExp = Math.round(totalExp * 5.0f);
                    }

                    if (totalExp > 0) {
                        // 生成经验球
                        ExperienceOrbEntity expOrb = new ExperienceOrbEntity(
                                world,
                                itemEntity.getX(),
                                itemEntity.getY() + 0.3,
                                itemEntity.getZ(),
                                totalExp
                        );
                        world.spawnEntity(expOrb);
                    }
                }

                // 替换掉落物为熔炼后的物品
                itemEntity.setStack(smeltedResult);

                // 添加熔炼粒子效果
                world.spawnParticles(
                        net.minecraft.particle.ParticleTypes.FLAME,
                        itemEntity.getX(), itemEntity.getY() + 0.2, itemEntity.getZ(),
                        5, 0.2, 0.2, 0.2, 0.05
                );

                // 添加经验粒子效果
                if (smeltingExp > 0) {
                    world.spawnParticles(
                            net.minecraft.particle.ParticleTypes.HAPPY_VILLAGER,
                            itemEntity.getX(), itemEntity.getY() + 0.3, itemEntity.getZ(),
                            3, 0.3, 0.1, 0.3, 0.1
                    );
                }
            }
        }
    }

    /**
     * 获取熔炼结果
     */
    private static ItemStack getSmeltedResult(ItemStack input, ServerWorld world) {
        if (input.isEmpty()) {
            return ItemStack.EMPTY;
        }

        SingleStackRecipeInput recipeInput = new SingleStackRecipeInput(input);
        var recipeOptional = world.getRecipeManager().getFirstMatch(RecipeType.SMELTING, recipeInput, world);

        if (recipeOptional.isPresent()) {
            var recipe = recipeOptional.get();
            ItemStack result = recipe.value().craft(recipeInput, world.getRegistryManager());
            result.setCount(input.getCount()); // 保持原有数量
            return result;
        }

        return ItemStack.EMPTY;
    }

    @Override
    public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity target, Vec3d pos) {
        // 逻辑在事件监听器中处理
    }

    @Override
    public MapCodec<? extends EnchantmentEntityEffect> getCodec() {
        return CODEC;
    }

    /**
     * 将所有掉落物聚合到中心位置
     */
    private static void gatherDropsToCenter(ServerWorld world, BlockPos centerPos, Set<BlockPos> harvestedBlocks) {
        // 计算搜索范围，覆盖所有挖掘的方块
        int minX = harvestedBlocks.stream().mapToInt(BlockPos::getX).min().orElse(centerPos.getX()) - 2;
        int maxX = harvestedBlocks.stream().mapToInt(BlockPos::getX).max().orElse(centerPos.getX()) + 2;
        int minY = harvestedBlocks.stream().mapToInt(BlockPos::getY).min().orElse(centerPos.getY()) - 2;
        int maxY = harvestedBlocks.stream().mapToInt(BlockPos::getY).max().orElse(centerPos.getY()) + 2;
        int minZ = harvestedBlocks.stream().mapToInt(BlockPos::getZ).min().orElse(centerPos.getZ()) - 2;
        int maxZ = harvestedBlocks.stream().mapToInt(BlockPos::getZ).max().orElse(centerPos.getZ()) + 2;

        // 创建搜索区域
        net.minecraft.util.math.Box searchBox = new net.minecraft.util.math.Box(minX, minY, minZ, maxX, maxY, maxZ);

        // 查找所有相关的掉落物
        List<ItemEntity> items = world.getEntitiesByClass(ItemEntity.class, searchBox,
                item -> item.isAlive() && item.age < 100); // 查找最近生成的掉落物

        // 目标位置：第一个挖掘方块的上方
        Vec3d targetPos = Vec3d.ofCenter(centerPos).add(0, 1.0, 0);

        for (ItemEntity item : items) {
            // 直接传送掉落物到目标位置
            item.setPosition(targetPos.x, targetPos.y, targetPos.z);
            item.setVelocity(0, 0, 0); // 清除速度，避免继续移动

            // 添加聚合粒子效果
            world.spawnParticles(
                    net.minecraft.particle.ParticleTypes.ENCHANT,
                    item.getX(), item.getY(), item.getZ(),
                    3, 0.2, 0.2, 0.2, 0.1
            );
        }

        // 同时聚合经验球
        List<net.minecraft.entity.ExperienceOrbEntity> expOrbs = world.getEntitiesByClass(
                net.minecraft.entity.ExperienceOrbEntity.class, searchBox,
                orb -> orb.isAlive());

        for (net.minecraft.entity.ExperienceOrbEntity orb : expOrbs) {
            orb.setPosition(targetPos.x, targetPos.y, targetPos.z);
            orb.setVelocity(0, 0, 0);
        }
    }

    /**
     * 获取熔炼配方的经验值
     *
     * @param itemStack 输入物品
     * @param world     世界
     * @return 熔炼经验值
     */
    private static float getSmeltingExperience(ItemStack itemStack, ServerWorld world) {
        if (itemStack.isEmpty()) {
            return 0.0f;
        }

        SingleStackRecipeInput recipeInput = new SingleStackRecipeInput(itemStack);
        var recipeOptional = world.getRecipeManager().getFirstMatch(RecipeType.SMELTING, recipeInput, world);

        if (recipeOptional.isPresent()) {
            var recipe = recipeOptional.get();
            if (recipe.value() instanceof SmeltingRecipe smeltingRecipe) {
                return smeltingRecipe.getExperience();
            }
        }

        return 0.0f;
    }
}